home *** CD-ROM | disk | FTP | other *** search
/ PCMania 64 / PCMania CD64_1.iso / phy / phy005 / files / articulo.t07 < prev    next >
Encoding:
Text File  |  1997-09-19  |  21.3 KB  |  1 lines

  1. ε                            Curso de assembler (V)                                  ε                            ----------------------                                                                                                                         En este nuevo número veremos todo lo concerniente a las instrucciones              δlógicasπ, profundizaremos en los registros y veremos que son los modos de           direccionamiento. Con lo aprendido en los anteriores números (bifurcaciones          y instrucciones aritméticas) más lo que veremos en este, deberiais ser ya            capaces de programar en ensamblador cositas sencillas usando interrupciones          y manipulando datos. Si todavia no sois capaces de hacerlo, seria muy                recomendable invertir más tiempo practicandolo ya que esa es la única forma          de aprender.                                                                           Antes de nada, cuando hablamos de las instrucciones de bifurcación se nos          quedó en el tintero la instrucción δLOOPπ. A esta instrucción se le pasa un          único parámetro que es una etiqueta donde saltará. Lo que hace es decrementar        φCXπ (CX=CX-1) y si CX no es 0 saltará a la etiqueta que le pasemos, sino            continuará por donde estaba. Un ejemplo:                                                                                                                                  Γ     ···                                                                            Γ     XOR  DX, DX            Ω    ;  DX = 0 (forma rápida de poner a 0).             Γ     MOV  CX, 100           Ω    ;  Repetir 100 veces.                              Γ  Bucle:                                                                            Γ     INC  DX                Ω    ;  DX = DX + 1                                     Γ     LOOP Bucle             Ω    ;  Si CX no es 0, repetir el bucle otra vez.       Γ     ···                    Ω    ;  En este punto, DX valdrà 100.                                                                                                                                                                                             φ         Instrucciones lógicas                                                                                                                                             Seguro que recordais las tablas de verdad que veiamos en los primeros              números de la Phy, ¿verdad? Pues las operaciones lógicas lo que hacen es             trabajar sobre estas tablas de verdad con registros o posiciones de memoria          de un tamaño en bits determinado. Por ejemplo, la tabla de la operación OR           era así:                                                                             Γ                0011                                                                Γ                0101                                                                Γ                ----                                                                Γ                0111                                                                                                                                                     Si por ejemplo tenemos en AL el valor binario <01001110> (recuerda que AL es         de 8 bits) y en BL tenemos el valor <11100110> y le aplicamos un δORπ de la          forma "OR AL,BL", el resultado será: AL=<11101110>.                                                                                                                       Γ                AL -> 01001110                                                      Γ                BL -> 11100110                                                      Γ                --------------    ΩOR   AL, BL                                      Γ                AL -> 11101110                                                                                                                                             Con la operación lógica δANDπ y δXORπ sucede exactamente lo mismo y como ya se     supone conoces sus tablas de verdad, no lo voy a volver a explicar. La última        operación lógica sí necesita un poco más de explicación ya que es un poco            diferente en su forma: la instrucción 'δNOTπ'.                                         'δNOTπ' se diferencia de las demás porque sólo necesita un operando y lo que       hace es invertir todos los bits del registro o posición de memoria (los unos         se hacen ceros y los ceros unos). Así de sencillas son las instrucciones             lógicas, solo recuerda que estas instrucciones modifican el estado de los            flags.                                                                                                                                                                    φ         Los registros                                                                                                                                                     Ya sé que ya hemos hablado antes de los registros, pero no esta todo dicho         pues nos centramos en lo que necesitabamos de inmediato que eran los registros       de uso general y un poco de los segmentos.                                             Los segmentos de memoria son un invento que se sacaron de la manga para            abaratar y simplificar la arquitectura de los primeros PCs. Aquella solución         aún hoy nos da quebraderos de cabeza cuando programamos en modo real (en             modo protegido las cosas cambian), pero no hay otra solución... :(                     Un segmento mide 64Kb (65535 bytes) ya que para direccionarlo usamos un            registro de segmento y otro que hace de índice dentro del segmento y que tiene       una longitud de 16 bits (2^16=64Kb). Un dato a tener en cuenta es la "granula-       ridad" de los segmentos, es decir, el solapamiento que se establece entre ellos      y que es de 16 bytes. Si cojemos el primer segmento, por ejemplo, el 0000h y         "avanzamos" 16 bytes, los datos que apartir de ahí nos encontremos, seran exac-      tamente iguales que los que haya a partir del segmento 0001h (esto puede expe-       rimentarse con el δDEBUGπ: entra y escribe la orden 'd 0000:0010' y luego escribe    'd 0001:0000' y observarás que el resultado es exactamente el mismo debido a         este solapamiento). Cuando veamos los modos de direccionamiento, veremos que         registros pueden hacer de índice y de base.                                            Registros de segmento hay varios: CS (code segment), DS (data segment),            SS (stack segment) y ES (extra segment). Los 3 primeros tienen una utilidad          clara y bien definida, mientras que el último se asemeja a un registro de uso        general. El registro CS es el que apunta al segmento de código, es decir donde       estan las instrucciones que se estan leyendo (volveremos cuando hablemos de          IP). El registro DS, en teoria, deberia apuntar a un segmento de datos que se        suele crear al inicio del programa, aunque puede apuntar a cualquier lugar           distinto. El segmento de pila (SS) es un segmento o parte de él usado para           guardar los datos que se "empujan" a la pila interna (de la que hablaremos           en próximos números) y las direcciones de retorno de subrutinas.                       Para cargar en un registro de segmento una dirección distinta se usa la            polivalente instrucción 'MOV', pero con algunas limitaciones. Con 'MOV' no           puedes modificar el registro CS aunque sí puedes coger su contenido y no puedes      cargar en los registros valores inmediatos. Veamos lo que se puede y no se pue-      de:                                                                                                                                                                       Γ    MOV     ES, [Variable]    Ω  ;  Se puede (mover una posición de memoria).       Γ    MOV     DS, 1000h         Ω  ;  No se puede (valor inmediato).                  Γ    MOV     CS, BX            Ω  ;  No se puede (modificar segmento de código).     Γ    MOV     AX, CS            Ω  ;  Se puede (leer valor del seg. de código).       Γ    SUB     ES, DS            Ω  ;  No se puede (usar cosas raras :).                                                                                                      Los registros δAX, BX, CX y DXπ son los llamados "de uso general" y no hay que     pensar que sus iniciales son porque los de Intel estaban ociosos y buscaron unas     iniciales que quedaran bien y pensaron en el abecedario (A+B+C+D)*X. La 'X'          viene de 'extended' ya que en las 2 partes en que se dividen (xL y xH) son las       simples y las otras las extendidas (por cierto, lo de AL y AH es por 'High'          y 'Low' y hace mención a la parte que ocupan en el registro extendido AX).           Lo realmente interesante es el porqué de la A, B, C y D, pues es una "causuali-      dad" muy curiosa que hace referencia al uso que en un principio se destinó para      los registros de "uso general" (si tenian un uso especifico, ¿porqué se les          llamó "de uso general"?).                                                              La 'δAπ' es la inicial de 'Acumulator', pues es donde se acumulan los valores      de algunas instrucciones aritméticas (p.e. la multiplicación). La 'δBπ' viene de     'Base' ya que es el registro de uso general que se puede usar como base en           algunos modos de direccionamiento (luego). La 'δCπ' es la inicial de 'Counter'       pues se usa como contador en instrucciones como 'LOOP' (comentada al principio).     Por último, la 'δDπ' es de 'Data' ya que será el único registro que nos quedará      libre para recibir los datos :)                                                        Cuando hablemos de los modos de direccionamiento le sacarás más partido a          los 2 registros que vienen ahora. Se trata de δSIπ (source index) y δDIπ (destina-   tion index) que en teoria tienen asignado el papel de registro de índice orígen      y destino, aunque en la práctica se pueden usar como se quiera. Los índices,         como se ha comentado antes, sirven para "direccionar" posiciones de memoria          dentro de los segmentos y hasta que no explique los modos de direccionamiento        no te sirven para nada :).                                                             Los registros δIPπ (index pointer) y δSPπ (stack pointer) son tambien 2 registros  índice como los anteriores, pero con una funcionalidad un tanto especial que         provoca que raramente se usen. El δIPπ apunta dentro del segmento de código (CS),    a la instrucción que en cada momento se está ejecutando, mientras que el δSPπ        apunta dentro del segmento de pila (SS) a la cima de dicha pila. El contenido        de IP no se puede modificar salvo por las instrucciones de salto, su comportamiento  es similar al de CS.                                                                   El último registro que nos queda es BP (base pointer) que como su nombre           indica hace de puntero base dentro de un segmento. Normalmente se asocia con         la pila y sin falta alguna de razón, ya que si no especificas a que registro         de segmento te refieres, usando BP se supone que es a SS (stack segment).                                                                                                 φ         Modos de direccionamiento                                                                                                                                         Lo de los modos de direccionamiento puede resultar bastante pesado de              aprender si te lo dan a "palo seco", sin ejemplos, sin una sóla instrucción.         Los nombres que adquieren los modos de direccionamiento son lo de menos, ya          los aprenderás con el tiempo por el uso, lo importante es qué se consigue con        cada uno de ellos. Voy a poner ejemplos de cosas que se pueden hacer y con el        nombre que recibe cada uno en el entorno PC.                                                                                                                              Γ    MOV  AX, 1054h      Ω<-  Direccionamiento inmediato                             Γ    MOV  AX, [1000h]    Ω<-  Dir. absoluto                                          Γ    MOV  CX, [BX]       Ω<-  Dir. indirecto con base (BX,BP)                        Γ    MOV  ES:[BP+5000h], BL                                                          Γ    MOV  AL, [BX+0100h]                                                             Γ    MOV  [DI+10], BL    Ω<-  Dir. indirecto con índice (DI,SI)                      Γ    MOV  BH, [SI+10]                                                                Γ    MOV  AL, [BX+SI]    Ω<-  Dir. indirecto con base (BX,BP) e índice (SI,DI)       Γ    MOV  CS:[BX+DI+50], BL                                                          Γ    MOV  [BP+SI+100], BH                                                            Γ    MOV  WORD PTR [BP+DI], 0010h                                                                                                                                           Como habrás podido apreciar, son sólo 5 los modos de direccionamiento que          existen en el modo real de un procesador Intel 80x86 y no demasiado difíciles.       Antes de comentarlos, observa tres pequeños detalles en las intrucciones anteriores. El primero, son esos registros de segmento (en concreto ES y CS) que aparecen        seguidos de ':' antes de algunos direccionamientos. La función de estos es           indicar a la instrucción que lo que ha de leer, no lo haga del segmento predeterminado                                                                                    sino del que se le indica antes de los ':'. Por ejemplo, con SI siempre se           busca por defecto en la zona de memoria apuntada por DS y si queremos que lea        de CS, lo que tenemos que hacer es anteponer 'CS:'.                                    El segundo detalle a observar, es en la última instrucción ese WORD PTR tan        raro que no habia salido nunca hasta ahora. Se usa para indicar al ensamblador       el tamaño de la instrucción ya que si no lo pusieramos no sabria si 0010h se         considera un BYTE o una WORD (cabe tanto en un 8 bits como en 16). Con 'WORD         PTR' le indicamos que el operando destino es una WORD y lo trata como debe. Si       hubiesemos especificado 'BYTE PTR', seria tratado como un BYTE.                        El tercer detalle y más importante, son los operandos que aparecen entre           corchetes. Cuando algo esta encerrado entre corchetes, inmediatamente hemos de       pensar que se trata de una posición de memoria, algo que se encuentra almacena-      do en RAM y que hemos de traer. Por ejemplo, ¿Que diferencia hay entre "MOV BX,      100h", "MOV BX,[100h]" y "MOV [BX],100h"? La primera, copiará en el registro BX      el valor 100h; la segunda, se irá a memoria (concretamente a la posición             DS:0100h) y leerá una WORD que copiará en BX; la tercera, cogerá el valor 100h       y lo guardará en la posición de memoria DS:BX (donde apunte el contenido de          BX).                                                                                   Volvamos a los modos de direccionamiento. El direccionamiento inmediato es         muy usado sobre todo para inicializar variables y registros. Hay gente que           no lo considera un modo de direccionamiento en sí mismo ya que se puede combi-       nar con otros como en la última instrucción o, por ejemplo:                                                                                                               Γ    MOV  WORD PTR DS:[BX+DI+1500h], 1000h                                           Γ    MOV  BYTE PTR [BX], 10h                                                                                                                                                El direccionamiento absoluto es usado muy frecuentemente en un programa ya         que todas las variables que no residan en registros se deben guardar en memoria      y para acceder a ellas se suele usar este modo pues es el más sencillo. Por          ejemplo, imagina un programa que te pida una letra por teclado y la almacene         en un determinado lugar de la memoria:                                                                                                                                    Γ    ····                                                                            Γ    Letra       DB      0                                                           Γ    ····                                                                            Γ    PideLetra:          Ω;  Función que guarda una tecla en Letra.                  Γ      XOR  AH, AH                                                                   Γ      INT  16h                 Ω ;  Pedir una tecla a la INT del teclado.           Γ      MOV  [Letra], AL         Ω ;  Dir. absoluto para guardar la tecla leida.      Γ      RET                                                                           Γ    ····                                                                            Γ    Main:                                                                           Γ      MOV  AX, CS                                                                   Γ      MOV  DS, AX              Ω ;  Por defecto DS que apunte a los datos.          Γ      CALL PideLetra           Ω ;  Llamamos a la función.                          Γ    ····                                                                                                                                                                   Los direccionamientos relativos a base o registros índice, se suelen usar          para fijar una dirección "base" en las lecturas y para recorrer arrays y             estructuras similares. Por ejemplo, tenemos una matriz de 500 elementos y            queremos hacer una función que devuelva en AX un 1 si no hay ningún elemento         con el valor 0 y un 0 en AX si hay elementos a 0:                                                                                                                         Γ    ····                                                                            Γ    Matriz      DB      32, 43, 243, 54, ···                                        Γ    ····                                                                            Γ    Check:                                                                          Γ      MOV  AX, 1            Ω    ;  Por defecto                                     Γ      MOV  BP, Offset MatrizΩ    ;  Dirección base -> el inicio de la matriz.       Γ      XOR  SI, SI           Ω    ;  SI <- 0, indice en la matriz a 0.               Γ     Bucle:                                                                         Γ      CMP  DS:[BP+SI], 0     Ω   ;  El elemento de [BP+SI] esta a 0?                Γ      JE  UnoCon0                                                                   Γ      INC  SI                Ω   ;  Siguiente elemento.                             Γ      CMP  SI, 100           Ω   ;  El último elemento?                             Γ      JB  Bucle                                                                     Γ      JMP Regresar           Ω   ;  Saltar para regresar.                           Γ     UnoCon0:                                                                       Γ      XOR  AX, AX            Ω   ;  Marcar como que hay elementos a 0.              Γ     Regresar:                                                                      Γ      RET                    Ω   ;  Volver al llamador.                             Γ    ····                                                                            Γ    Main:                                                                           Γ      ····                                                                          Γ      CALL  Check                                                                   Γ      OR    AX, AX           Ω   ;  Lo mismo que 'CMP AX,0' pero más corto.         Γ      JE   HayCeros                                                                 Γ    ····                                                                                                                                                                   Este pedazo de código que aparentemente no tiene ninguna utilidad real,            en determinados ámbitos de la programación puede usarse muchas veces (cosas          similares) como en la programación gràfica para ver si en la pantalla hay            algún pixel con el color 0. Recordatorio: en la línea donde se inicializa el         registro base, se ha usado la palabra clave 'offset XX', significa "el despla-       zamiento dentro del segmento correspondiente hasta la variable XX".                                                                                                         En el número de hoy hemos dado un somero repaso a todos los conceptos e ideas      que ya habiamos expuesto y que faltaba consolidar por lo que hemos ido tirando       de teoria todo el rato. Para el próximo número os prometo que la cosa será mu-       cho más práctica y con varios programas para ensamblar. Veremos todo lo rela-        cionado con la pila interna, algunas instruciones nuevas y algún ejemplo rela-       cionado con los gráficos o la VGA, ya veremos...                                                                                                                                                                                 ∞  Navi/PhyMosys